#!/usr/bin/env python
# coding=UTF-8
import logging
import time
import datetime
from hashlib import md5
import urllib, urllib2
import random, json
import config
import dao
# import requests
import cherrypy
import redis
from nsq.http import nsqd

def nsq_pub(topic, message):
    try:
        nsq_client = nsqd.Client("http://47.93.90.95:4151/")
        if isinstance(message, dict):
            message = json.dumps(message, separators=(',', ':'))
        logging.info(message)
        nsq_client.pub(topic, message)
        return True
    except:
        logging.error("nsq send error", exc_info=True)
        return False

pool = redis.ConnectionPool(host=config.REDIS_HOST, port=config.REDIS_PORT, db=config.REDIS_DB)
_r = redis.Redis(connection_pool=pool)

def get_client_ip():
    header = cherrypy.request.headers
    ip = ''
    ipList = header.get("X-Forwarded-For", "").replace(" ", "").split(",")
    if ipList:
        # for p in ipList:
        #    if p[:2] == '10' or p[:3] in ('127', '192', '172'):
        #        continue
        #    else:
        #        ip = p
            
        ip = ipList[0]
        if len(ipList) > 1 and (ip[:2] == '10' or ip[:3] in ('127', '192', '172')):
            ip = ipList[1]
    if not ip:
        ip = header.get('X-Real-Ip')
    if not ip:
        ip = header.get('Remote-Addr')
    if not ip:
        ip = header.get('REMOTE-ADDR')
    return ip

def get_phone_model(ua=''):
    if not ua:
        header = cherrypy.request.headers
        ua = header.get("User-Agent", "")
    if "Android" in ua:
        info = ua.split(";")[-1].strip()
        return info.split("Build")[0].strip()
    elif "iPhone" in ua:
        return "iPhone"
    return ""

def get_wx_user(access_token, openid):
    try:
        url = "http://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" % (access_token, openid)
        # h = requests.get(url, verify=False)
        # res = h.json()
        logging.info(url)
        h = urllib2.urlopen(url)
        res = h.read()
        logging.info(res)
        res = json.loads(res)
        return res
    except:
        logging.error("wx api error", exc_info=True)
        return {}

def conf(cp, cv, bid, uid):
    conf_info = {}
    update_info = {}
    db = dao.Game_DB()
    conf_list = db.get_conf(bid)
    if conf_list:
        for conf in conf_list:
            conf_info[conf['param']] = conf['value']
    if cp == 'ios' and cv == conf_info.get('ios_version'):
        wx_login = 'n'
        guest_login = 'y'
    else:
        wx_login = 'y'
        guest_login = 'y'
    update_info['new_cv'] = '2.0.0'
    update_info['url'] = 'http://m.99ok.com.cn'
    update_info['tips'] = '新版更新提示说明新版更新提示说明新版更新提示说明新版更新提示说明新版更新提示说明新版更新提示说明'
    update_info['force_update'] = 'n'
    game_rule = []
    return {"code":0, "msg":"ok", "data":{"conf_info":conf_info, "update_info":update_info, "wx_login":wx_login, "guest_login":guest_login, "game_rule":game_rule}}

def user_info(bid, uid):
    db = dao.Game_DB()
    data = db.user_info(bid, uid)
    del data['ctime']
    del data['pwd']
    del data['md5pwd']
    return {"code":0, "msg":"ok", "data":data}

def login(cp, cv, bid, access_token, openid, devid, login_type):
    db = dao.Game_DB()
    if login_type == 'wx':
        devid = ''
        if not openid:
            return {"code":1000, "msg":"openid not null"}
        user_info = db.get_wx_user(bid, openid)
    else:
        user_info = db.get_dev_user(bid, devid)
    ip = get_client_ip()
    if user_info:
        user_info.pop("ctime")
        user_info['pwd'] = user_info['md5pwd']
        user_info.pop("md5pwd")
        get_joined_room = db.get_joined_room(bid, user_info['uid'])
        if get_joined_room:
            joined_room = get_joined_room['rid']
        else:
            joined_room = 0
        user_info['ip'] = ip
        key = "%s_%s" % (bid, str(user_info['uid']))
        _r.hmset(key, user_info)
        return {"code":0, "msg":"登录成功",
                "data":{"user_info":user_info,
                        "joined_room":joined_room,
                        "tcp_server":{"ip":"47.93.90.95", "port":8098},
                        }
                }

    max_uid = db.get_max_uid(bid)
    if not (max_uid and max_uid['uid']):
        uid = 100001
    else:
        uid = long(max_uid['uid']) + 1
        
    if login_type == 'wx':
        wx_user_info = get_wx_user(access_token, openid)
        if not wx_user_info or not wx_user_info.get("openid"):
            return {"code":1001, "msg":"登录失败,获取微信信息异常"}
        head = wx_user_info['headimgurl']
        name = wx_user_info['nickname']
        sex = wx_user_info['sex']
    else:
        head = "http://api.99ok.com.cn/voice/head/%s.png" % (uid % 16 + 1)
        phone_model = get_phone_model()
        if phone_model:
            name = phone_model
        else:
            name = u"游客"
        sex = 1
        openid = ""
    card = 2
    pwd = str(random.randint(100000, 999999))
    pid = 0
    i = db.add_user(bid, uid, pwd, openid, head, name, sex, cp, cv, card, pid, devid)
    if i != 1:
        db.res = False
        return {"code":1001, "msg":"注册账户异常"}
    user_info = {"uid":uid, "pwd":md5(pwd).hexdigest(), "head":head, "name":name, "sex":sex, "ip":ip, "card":card}
    key = "%s_%s" % (bid, str(uid))
    _r.hmset(key, user_info)
    return {"code":0, "msg":"登录成功",
            "data":{"user_info":user_info,
                    "joined_room":0,
                    "tcp_server":{"ip":"47.93.90.95", "port":8098},
                    }
            }
        
def create_room(cp, cv, bid, uid, pwd, player, game_type, all_round, gps_lat, gps_lon, rule):
    ip = get_client_ip()
    all_round = int(all_round)
    if all_round == 8:
        card = 1
    elif all_round == 16:
        card = 2
    else:
        return {"code":1100, "msg":"all_round error"}
    
    rules = {}
    if rule:
        for r in rule.split(","):
            k, v = r.split("=")
            rules[k] = v
            
    horse = int(rules.get("horse", 0))
    grab_bar_win = rules.get("grab_bar_win", "n")
    grab_bar_duty = rules.get("grab_bar_duty", "n")
    bar_win_duty = rules.get("bar_win_duty", "n")
    seven_pair_win = rules.get("seven_pair_win", "n")
    player = int(player)
    if game_type == 'gdmj':
        player = 4
        
    db = dao.Game_DB()
    user_info = db.user_info(bid, uid)
    get_joined_room = db.get_joined_room(bid, uid)
    if get_joined_room:
        return {"code":1100, "msg":"请先退出之前加入的房间"}
        #if str(get_joined_room['admin']) != uid:
        #    return {"code":1100, "msg":"请先退出之前加入的房间"}
        #rid = get_joined_room['rid']
        #return {"code":0, "msg":"ok", "data":{"sex":user_info['sex'], "ip":ip, "base_score":1000, "rid":rid, "share_url":"http://wap.99ok.com.cn/?rid=%s" % get_joined_room['rid'], "share_title":u"麻将<推到胡>房间号:【%s】 【点击进入】" % get_joined_room['rid'], "share_des":u"%s马, %s局, 可七对,十三幺" % (horse, all_round)}} 
    
    if user_info['card'] < card:
        return {"code":1101, "msg":"您的账户房卡不足"}
    try:
        # 创建房间
        (i, rid) = db.add_room(bid, game_type, uid, all_round, card, player)
        for k, v in rules.iteritems():
            db.add_room_rule(rid, k, v)

        share_title = u"麻将"
        if game_type == 'zzmj':
            share_title += u"<转转麻将>"
        elif game_type == 'gdmj':
            share_title += u"<广东麻将推到胡>"
        share_title += u" 房间号:【%s】 【点击进入】" % rid
        
        share_des = u""
        horse = int(rules.get("horse", 0))
        if horse:
            share_des += u"%s马,%s局" % (horse, all_round)
        else:
            share_des += u"无马,%s局" % all_round
        if rules.get("seven_pair_win") == 'y':
            share_des += u",可胡七对"
        if rules.get("grab_bar_win") == 'y':
            share_des += u",可抢杠胡"
        if rules.get("bar_win_duty") == 'y':
            share_des += u",杠爆全包"
        # 添加房主玩家
        db.add_player(rid, uid, 1, 'y', ip, gps_lat, gps_lon, 1)
        # 创建其他玩家座位
        for seat in range(2, player + 1):
            db.add_player(rid, 0, 0, 'n', '', '', '', seat)
        if not nsq_pub("status", {"b":bid, "u":uid, "d":{"act":"create_room", "uid":uid, "rid":rid, "bid":bid, "player":player, "card":card, "all_round":all_round, "game_type":game_type, "horse":horse, "grab_bar_win":grab_bar_win, "grab_bar_duty":grab_bar_duty, "bar_win_duty":bar_win_duty, "seven_pair_win":seven_pair_win}}):
            db.res = False
            return {"code":1102, "msg":"处理超时"}
        return {"code":0, "msg":"ok", "data":{"rules":rules, "sex":user_info['sex'], "ip":ip,"base_score":1000, "rid":rid, "share_url":"http://wap.99ok.com.cn/?rid=%s" % rid, "share_title":share_title, "share_des":share_des}}
    except:
        db.res = False
        logging.error("create room error:", exc_info=True)
        return {"code":1103, "msg":"创建失败"}
    
def join_room(cp, cv, bid, uid, pwd, rid, gps_lat, gps_lon):
    ip = get_client_ip()
    db = dao.Game_DB()
    user_info = db.user_info(bid, uid)
    room_info = db.get_room(rid, bid)
    if not room_info:
        return {"code":1200, "msg":"该房间不存在"}
    if room_info['flag'] != 'y':
        return {"code":1201, "msg":"该房间已结束"}
    room = _r.hgetall("r:%s" % rid)
    if room.get('dealer'):
        room_info['dealer'] = int(room['dealer'])
        room_info['game_round'] = int(room['game_round'])
    else:
        room_info['dealer'] = room_info['admin']
    room_info.pop("ctime")
    get_joind_room = db.get_joined_room(bid, uid)
    if get_joind_room:
        # 重返房间
        if get_joind_room['rid'] != int(rid):
            return {"code":1202, "msg":"该帐号已在其他房间,请先退出"}
        seat = get_joind_room['seat']
        i = db.return_room(rid, seat, uid, 0, 'y', ip, gps_lat, gps_lon)
        i = 1
    else:
        # 新加入房间
        row = db.get_free_seat(rid)
        if not row:
            return {"code":1202, "msg":"该房间人员已满"}
        seat = row['seat']
        i = db.join_room(rid, seat, uid, 0, 'y', ip, gps_lat, gps_lon)
    if i != 1:
        db.res = False
        return {"code":1203, "msg":"进入房间失败"}
    if not nsq_pub("status", {"b":bid, "u":uid, "d":{"act":"join_room", "uid":uid, "rid":rid, "bid":bid, "ip":ip, "gps_lat":gps_lat, "gps_lon":gps_lon, "seat":seat, "score":1000, "head":user_info['head'], "name":user_info['name'], "sex":user_info['sex']}}):
        db.res = False
        return {"code":1204, "msg":"处理超时"}
    # 获取房间所有玩家信息
    players = db.query_room_players(rid, bid)
    rules = {}
    rows = db.room_rule(rid)
    for row in rows:
        k = row['param']
        rules[k] = row['value']
    share_title = u"麻将"
    if room_info['game_type'] == 'zzmj':
        share_title += u"<转转麻将>"
    elif room_info['game_type'] == 'gdmj':
        share_title += u"<广东麻将推到胡>"
    share_title += u" 房间号:【%s】 【点击进入】" % rid
    
    share_des = u""
    all_round = rules.get("all_round", 8)
    horse = int(rules.get("horse", 0))
    if horse:
        share_des += u"%s马,%s局" % (horse, all_round)
    else:
        share_des += u"无马,%s局" % all_round
    if rules.get("seven_pair_win") == 'y':
        share_des += u",可胡七对"
    if rules.get("grab_bar_win") == 'y':
        share_des += u",可抢杠胡"
    if rules.get("bar_win_duty") == 'y':
        share_des += u",杠爆全包"
        
    return {"code":0, "msg":"ok", "data":{"rules":rules, "base_score":1000, "room_info":room_info, "players":players, "seat":seat, "share_url":"http://wap.99ok.com.cn/?rid=%s" % rid, "share_title":share_title, "share_des":share_des}}

def quit_room(cp, cv, bid, uid, pwd, rid):
    rid = int(rid)
    db = dao.Game_DB()
    room_info = db.get_room(rid, bid)
    if not room_info:
        return {"code":1300, "msg":"该房间不存在"}
    get_joined_room = db.get_joined_room(bid, uid)
    if not get_joined_room:
        return {"code":1301, "msg":"该帐号未进入房间无需退出"}
    status = _r.hget("r:%s" % rid, "status")
    if status:
        return {"code":1302, "msg":"游戏进行中,不能退出房间"}
    if room_info['admin'] == long(uid):
        i = db.admin_quit_room(rid, uid)
        joined_room = rid
    else:
        i = db.quit_room(rid, uid)
        joined_room = ""
    if i != 1:
        db.res = False
        return {"code":1303, "msg":"房间退出失败"}
    if not nsq_pub("status", {"b":bid, "u":uid, "d":{"act":"quit_room", "uid":uid, "rid":rid, "bid":bid}}):
        db.res = False
        return {"code":1304, "msg":"处理超时"}
    return {"code":0, "msg":"ok", "data":{"joined_room":joined_room}}

def dismiss_room(cp, cv, bid, uid, pwd, rid):
    rid = int(rid)
    db = dao.Game_DB()
    room_info = db.get_room(rid, bid)
    if not room_info:
        return {"code":1400, "msg":"该房间不存在"}
    if room_info['admin'] != long(uid):
        return {"code":1401, "msg":"你不是该房间的房主,不能解散"}
    room_player_cnt = db.room_player_cnt(rid)
    if room_player_cnt['player'] == room_info['player']:
        return {"code":1401, "msg":"游戏已准备,不能解散"}
    i = db.dismiss_room(rid, bid, uid)
    if i != 1:
        db.res = False
        return {"code":1302, "msg":"房间退出失败"}
    if not nsq_pub("status", {"b":bid, "u":uid, "d":{"act":"dismiss_room", "uid":uid, "rid":rid, "bid":bid}}):
        db.res = False
        return {"code":1303, "msg":"处理超时"}
    return {"code":0, "msg":"ok"}
    
def game_des(cp, cv, bid, uid):
    db = dao.Game_DB()
    conf_list = db.get_game_des()
    if not conf_list:
        conf_list = []
    return {"code":0, "msg":"ok", "data":{'game_list':conf_list}}

def feedback(bid, uid, content):
    db = dao.Game_DB()
    db.add_feedback(bid, uid, content)
    return {"code":0, "msg":"ok"}

def game_start(rid, bid):
    nsq_pub("game", {"b":"szjt", "u":"", "t":"game", "d":{"act":"game_start", "rid":rid}})
    return "ok"

if __name__ == '__main__':
    print get_phone_model('Dalvik/2.1.0 (Linux; U; Android 5.1; vivo X6D Build/LMY47I)')
